{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:26:05.966845Z",
     "start_time": "2021-02-18T02:26:05.955833Z"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import pickle\n",
    "import random\n",
    "from tqdm import tqdm\n",
    "from time import time\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "plt.style.use('fivethirtyeight')\n",
    "\n",
    "from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau\n",
    "from tensorflow.keras.optimizers import Adam\n",
    "from tensorflow.keras.metrics import AUC\n",
    "from tensorflow.keras.losses import binary_crossentropy\n",
    "\n",
    "from DIN import DIN\n",
    "from data_crecate import create_amazon_electronic_dataset\n",
    "\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:20:33.701466Z",
     "start_time": "2021-02-18T02:20:24.637678Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=========Data Preprocess Start===========\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|███████████████████████████████████████████████████████████████████████| 100000/100000 [00:07<00:00, 12991.31it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "=================Padding================\n",
      "===========Data Preprocess End====================\n"
     ]
    }
   ],
   "source": [
    "\"\"\"数据生成\"\"\"\n",
    "file_name = './dataset/remap.pkl'\n",
    "feature_columns, behavior_list, (train_X, train_y), (val_X, val_y), (test_X, test_y) = create_amazon_electronic_dataset(file_name)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:20:41.152542Z",
     "start_time": "2021-02-18T02:20:41.149508Z"
    },
    "run_control": {
     "marked": true
    }
   },
   "outputs": [],
   "source": [
    "\"\"\"超参数设置\"\"\"\n",
    "maxlen = 40\n",
    "embed_dim = 8\n",
    "att_hidden_units = [80, 40]\n",
    "ffn_hidden_units = [256, 128, 64]\n",
    "dnn_dropout = 0.5\n",
    "att_activation = 'sigmoid'\n",
    "ffn_activation = 'prelu'\n",
    "\n",
    "learning_rate = 0.001\n",
    "batch_size = 64\n",
    "epochs = 50"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:20:43.045436Z",
     "start_time": "2021-02-18T02:20:42.741251Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"model\"\n",
      "__________________________________________________________________________________________________\n",
      "Layer (type)                    Output Shape         Param #     Connected to                     \n",
      "==================================================================================================\n",
      "input_4 (InputLayer)            [(None, 1)]          0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_3 (InputLayer)            [(None, 40, 1)]      0                                            \n",
      "__________________________________________________________________________________________________\n",
      "tf.__operators__.getitem_2 (Sli (None,)              0           input_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "tf.__operators__.getitem_1 (Sli (None, 40)           0           input_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "tf.__operators__.getitem (Slici (None, 40)           0           input_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "embedding (Embedding)           multiple             218128      tf.__operators__.getitem_1[0][0] \n",
      "                                                                 tf.__operators__.getitem_2[0][0] \n",
      "__________________________________________________________________________________________________\n",
      "tf.math.not_equal (TFOpLambda)  (None, 40)           0           tf.__operators__.getitem[0][0]   \n",
      "__________________________________________________________________________________________________\n",
      "tf.identity_1 (TFOpLambda)      (None, 8)            0           embedding[1][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "tf.identity (TFOpLambda)        (None, 40, 8)        0           embedding[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "tf.cast (TFOpLambda)            (None, 40)           0           tf.math.not_equal[0][0]          \n",
      "__________________________________________________________________________________________________\n",
      "attention_layer (Attention_laye (None, 8)            5921        tf.identity_1[0][0]              \n",
      "                                                                 tf.identity[0][0]                \n",
      "                                                                 tf.identity[0][0]                \n",
      "                                                                 tf.cast[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "tf.concat (TFOpLambda)          (None, 16)           0           attention_layer[0][0]            \n",
      "                                                                 tf.identity_1[0][0]              \n",
      "__________________________________________________________________________________________________\n",
      "batch_normalization (BatchNorma (None, 16)           64          tf.concat[0][0]                  \n",
      "__________________________________________________________________________________________________\n",
      "dense_3 (Dense)                 (None, 256)          4608        batch_normalization[0][0]        \n",
      "__________________________________________________________________________________________________\n",
      "dense_4 (Dense)                 (None, 128)          33024       dense_3[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dense_5 (Dense)                 (None, 64)           8320        dense_4[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dropout (Dropout)               (None, 64)           0           dense_5[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "dense_6 (Dense)                 (None, 1)            65          dropout[0][0]                    \n",
      "__________________________________________________________________________________________________\n",
      "input_1 (InputLayer)            [(None, 0)]          0                                            \n",
      "__________________________________________________________________________________________________\n",
      "input_2 (InputLayer)            [(None, 0)]          0                                            \n",
      "__________________________________________________________________________________________________\n",
      "tf.math.sigmoid (TFOpLambda)    (None, 1)            0           dense_6[0][0]                    \n",
      "==================================================================================================\n",
      "Total params: 270,130\n",
      "Trainable params: 270,098\n",
      "Non-trainable params: 32\n",
      "__________________________________________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "\"\"\"模型建立\"\"\"\n",
    "model = DIN(feature_columns, behavior_list, att_hidden_units, ffn_hidden_units, att_activation, ffn_activation, maxlen, dnn_dropout)\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:20:45.500867Z",
     "start_time": "2021-02-18T02:20:45.485950Z"
    }
   },
   "outputs": [],
   "source": [
    "\"\"\"模型编译\"\"\"\n",
    "model.compile(loss=binary_crossentropy, optimizer=Adam(learning_rate=learning_rate), metrics=[AUC()])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:20:58.418360Z",
     "start_time": "2021-02-18T02:20:46.661764Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50\n",
      "303/303 [==============================] - 3s 6ms/step - loss: 0.5946 - auc: 0.7442 - val_loss: 0.7480 - val_auc: 0.8460\n",
      "Epoch 2/50\n",
      "303/303 [==============================] - 1s 5ms/step - loss: 0.1950 - auc: 0.9783 - val_loss: 0.4486 - val_auc: 0.8951\n",
      "Epoch 3/50\n",
      "303/303 [==============================] - 1s 5ms/step - loss: 0.0513 - auc: 0.9986 - val_loss: 0.7335 - val_auc: 0.8884\n",
      "Epoch 4/50\n",
      "303/303 [==============================] - 1s 5ms/step - loss: 0.0252 - auc: 0.9997 - val_loss: 0.9171 - val_auc: 0.8756\n",
      "Epoch 5/50\n",
      "303/303 [==============================] - 1s 5ms/step - loss: 0.0234 - auc: 0.9996 - val_loss: 0.9259 - val_auc: 0.8732\n",
      "\n",
      "Epoch 00005: ReduceLROnPlateau reducing learning rate to 1.0000000474974514e-05.\n",
      "Epoch 6/50\n",
      "303/303 [==============================] - 2s 5ms/step - loss: 0.0255 - auc: 0.9995 - val_loss: 0.8943 - val_auc: 0.8764\n",
      "Epoch 7/50\n",
      "303/303 [==============================] - 1s 5ms/step - loss: 0.0177 - auc: 0.9999 - val_loss: 0.8851 - val_auc: 0.8779\n"
     ]
    }
   ],
   "source": [
    "\"\"\"模型训练\"\"\"\n",
    "callbacks = [\n",
    "    EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True),   # 早停\n",
    "    ReduceLROnPlateau(monitor='val_loss', patience=3, factor=0.01, verbose=1)  # 调整学习率\n",
    "]\n",
    "history = model.fit(train_X, \n",
    "                    train_y, \n",
    "                    epochs=epochs, \n",
    "                    validation_data=(val_X, val_y), \n",
    "                    batch_size=batch_size,\n",
    "                    callbacks = callbacks\n",
    "                   )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:26:11.213230Z",
     "start_time": "2021-02-18T02:26:11.068157Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\"\"\"可视化下看看训练情况\"\"\"\n",
    "plt.plot(history.history['loss'])\n",
    "plt.plot(history.history['val_loss'])\n",
    "plt.title('Model loss')\n",
    "plt.ylabel('Loss')\n",
    "plt.xlabel('Epoch')\n",
    "plt.legend(['Train', 'Test'], loc='upper left')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里发现1个epoch的时候，后面就开始过拟合了。我这次用的数据量太小了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2021-02-18T02:26:21.567143Z",
     "start_time": "2021-02-18T02:26:20.108973Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1054/1054 [==============================] - 1s 1ms/step - loss: 1.1714 - auc: 0.6439\n",
      "test AUC: 0.643948\n"
     ]
    }
   ],
   "source": [
    "\"\"\"模型评估\"\"\"\n",
    "print('test AUC: %f' % model.evaluate(test_X, test_y)[1])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
